package io.github.talelin.latticy.service.impl;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.github.talelin.latticy.bo.LocationByAreaVo;
import io.github.talelin.latticy.bo.StockBO;
import io.github.talelin.latticy.bo.StockOnTheWayBO;
import io.github.talelin.latticy.common.util.PageUtil;
import io.github.talelin.latticy.common.util.SnowFlake;
import io.github.talelin.latticy.dto.stock.StockAdjustDTO;
import io.github.talelin.latticy.dto.stock.StockDTO;
import io.github.talelin.latticy.dto.stock.StockPageDTO;
import io.github.talelin.latticy.dto.stock.StockVO;
import io.github.talelin.latticy.model.LocationDO;
import io.github.talelin.latticy.model.MsgLogDO;
import io.github.talelin.latticy.model.StockDO;
import io.github.talelin.latticy.mapper.StockMapper;
import io.github.talelin.latticy.mq.MessageHelper;
import io.github.talelin.latticy.service.LocationService;
import io.github.talelin.latticy.service.MsgLogService;
import io.github.talelin.latticy.service.StockService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.github.talelin.latticy.util.PageHelpUtil;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 库存 服务实现类
 * </p>
 *
 * @author generator@wulongbo
 * @since 2022-06-28
 */
@Service
public class StockServiceImpl extends ServiceImpl<StockMapper, StockDO> implements StockService {

    @Autowired
    private RabbitTemplate rabbitTemplate;


    @Autowired
    private MsgLogService msgLogService;

    @Autowired
    private LocationService locationService;


    @Override
    public IPage<StockVO> getStockList(StockPageDTO stockPageDTO) {
        QueryWrapper<StockDO> wrapper= new QueryWrapper<>();
        boolean isSql=false;
        String inSql = "";
        if(Objects.nonNull(stockPageDTO.getMin()) && Objects.nonNull(stockPageDTO.getMax())&&  Objects.nonNull(stockPageDTO.getStockType())){
            isSql=true;
            inSql=String.format(" AND %s BETWEEN %s AND %S",stockPageDTO.getStockType().getStockTypeDesc(),stockPageDTO.getMin(),stockPageDTO.getMax());
        }
        Page<StockDO> page = this.page(new Page<>(stockPageDTO.getCurrPage(), stockPageDTO.getPageSize()),wrapper
                .eq(StrUtil.isNotEmpty(stockPageDTO.getWarehouseCode()), "warehouse_code", stockPageDTO.getWarehouseCode())
                .like(StrUtil.isNotEmpty(stockPageDTO.getSku()), "sku", stockPageDTO.getSku())
                .like(StrUtil.isNotEmpty(stockPageDTO.getCustomerCode()),"tenant" , stockPageDTO.getCustomerCode())
                .last(isSql,inSql));
        return PageHelpUtil.convertPage(page, StockVO.class);
    }




    @Override
    public StockDO getStockByWarehouseCodeAndCustomerCodeAndSku(String warehouseCode, String customerCode, String sku) {
        return baseMapper.selectOne(new LambdaQueryWrapper<StockDO>().eq(StockDO::getWarehouseCode, warehouseCode)
                .eq(StockDO::getTenant, customerCode)
                .eq(StockDO::getSku, sku));
    }


    @Override
    public Boolean insertOrUpStock(StockDTO stockDTO) {
        StockDO stock = this.getStockByWarehouseCodeAndCustomerCodeAndSku(stockDTO.getWarehouseCode(), stockDTO.getCustomerCode(), stockDTO.getSku());
        if (Objects.isNull(stock)) {
            StockDO stockDO = new StockDO();
            stockDO.setWarehouseCode(stockDTO.getWarehouseCode());
            stockDO.setSku(stockDTO.getSku());
            stockDO.setSkuName(stockDTO.getSkuName());
            stockDO.setTenant(stockDTO.getCustomerCode());
            stockDO.setOnThePutAway(stockDTO.getQuantity());
            stockDO.setCreateTime(new Date());
            return save(stockDO);
        }
        StockDO stockDO = new StockDO();
        stockDO.setId(stock.getId());
        stockDO.setOnThePutAway(stockDTO.getQuantity() + stock.getOnTheWay());
        return updateById(stockDO);
    }



    @Override
    public void deliveryOnTheWayStock(List<StockBO> stockBOS) {
        //生成消息id
        SnowFlake idWorker = new SnowFlake(0, 0);
        Long msgId = idWorker.nextId();
        StockOnTheWayBO stockOnTheWayBO=new StockOnTheWayBO(msgId,stockBOS);
        MsgLogDO msgLog = new MsgLogDO(msgId, stockOnTheWayBO, "inbound.order.no.exchange", "inbound.order.no.queue.key");
        msgLogService.createMsgLog(msgLog);// 消息入库
        CorrelationData correlationData = new CorrelationData(String.valueOf(msgId));
        rabbitTemplate.convertAndSend("inbound.order.no.exchange", "inbound.order.no.queue.key", MessageHelper.objToMsg(stockOnTheWayBO), correlationData);
    }

    @Override
    public boolean adjustStock(List<StockAdjustDTO> stockDTO) {
        //1.获取对应的sku库存情况
        List<String> skuList = stockDTO.parallelStream().map(StockAdjustDTO::getSku).distinct().collect(Collectors.toList());
        LambdaQueryWrapper<StockDO> stockWrapper = new LambdaQueryWrapper<>();
        stockWrapper
                .eq(StockDO::getWarehouseCode,stockDTO.get(0).getWarehouseCode())
                .eq(StockDO::getTenant,stockDTO.get(0).getCustomerCode())
                .in(StockDO::getSku,skuList);
        List<StockDO> stockDOList = this.list(stockWrapper);
        //2.根据库位获取对应的库位分区更改对应的库存
        List<Integer> locationIdList = stockDTO.parallelStream().map(StockAdjustDTO::getLocationId).distinct().collect(Collectors.toList());
        List<LocationByAreaVo> locationByIdList = locationService.getLocationByIdList(locationIdList);
        Assert.isTrue(CollectionUtils.isNotEmpty(locationByIdList),"18502");
        //将库位列表进行分组 TODO
        Map<Integer, LocationByAreaVo> areaVoMap = locationByIdList.parallelStream().collect(Collectors.toMap(LocationByAreaVo::getId, locationByAreaVo -> locationByAreaVo, (k1, k2) -> k1));
        //将调整库存列表进行分组
        Map<String, StockAdjustDTO> adjustDTOMap = stockDTO.parallelStream().collect(Collectors.toMap(StockAdjustDTO::getSku, stockAdjust -> stockAdjust, (k1, k2) -> k1));
        stockDOList=stockDOList.parallelStream().map(stockDO -> {
            StockAdjustDTO stockAdjustDTO = adjustDTOMap.get(stockDO.getSku());
            if(stockAdjustDTO.getType()==1){
                stockDO.setAvailableStock(stockAdjustDTO.getQuantity());
            }else if(stockAdjustDTO.getType()==2){
                stockDO.setAvailableStock(stockDO.getAvailableStock()+stockAdjustDTO.getQuantity());
            }
            return stockDO;
        }).collect(Collectors.toList());
        return this.updateBatchById(stockDOList);
    }
}
